import struct

from PyQt5.Qt import *
from UI.mainwindow import Ui_MainWindow
from typing import *
import sys
import pyqtgraph as pg
import os
import cgitb
import json

import warnings

warnings.filterwarnings('ignore')
cgitb.enable(format='txt')
pg.setConfigOptions(antialias=True)
from windows.setting_v2 import SettingDockWidget
from windows.testdockwidget import TestDockWidget
from windows.traindockwidget import DockWidget
from windows.dialog import TrainDialog
from windows.selectWin import SelectWindow
from ExtendWidgets.notifycation import NotificationWindow
import numpy as np
import scipy
from scipy.fftpack import fftshift
from scipy.signal import stft
import scipy.signal
from ExtendWidgets.little_widgets import Level_2_Widget, Level_3_Project_Widget
from pprint import pprint
from ExtendWidgets.ETreeWidget import ETreeWidget, ETreeWidgetItem
import re


def IQ_to_PSD(IQ, iq_complex_cnt, nfft, Fs, noverlap, nperseg):
    I_index = np.arange(0, iq_complex_cnt * 2, 2)
    Q_index = np.arange(1, iq_complex_cnt * 2, 2)
    window = scipy.signal.get_window('hamming', Nx=nfft)
    I = IQ[I_index]
    Q = IQ[Q_index]
    IQ_complex = np.zeros([iq_complex_cnt], dtype=np.complex)
    IQ_complex.real = I
    IQ_complex.imag = Q
    F, T, Zxx = stft(IQ_complex, fs=Fs, noverlap=noverlap, nfft=nfft, window=window,
                     return_onesided=False,
                     nperseg=nperseg)
    s: np.ndarray = fftshift(np.log(np.abs(Zxx) * 2 / nfft))
    return s


class MainWin(Ui_MainWindow, QMainWindow):
    windowSizeChanged = pyqtSignal()

    def __init__(self, parent=None):
        super(MainWin, self).__init__(parent)
        # self.setWindowFlags(Qt.CustomizeWindowHint)
        center = self.takeCentralWidget()
        self.unnameid = 0
        del center
        self.created_select_win = False
        self.setDockNestingEnabled(True)
        self.setWindowIcon(QIcon("images/WIcon.png"))
        self.setting_dock = SettingDockWidget(self)
        self.setting_dock.showMinimized()
        self.setting_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.docks: List[Union[DockWidget, TestDockWidget]] = []
        self.needToDeleteDocks: List[Union[DockWidget, TestDockWidget]] = []
        self.dock_id = 0
        self.setupUi(self)
        self.__connectSlot()
        self.InitLayout()

        # self.initSetting()
        self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.toolBar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.NoContextMenu)
        img = QImage()
        img.load("./images/频谱异常检测软件.jpg")
        label = QLabel(self)
        pixmap = QPixmap.fromImage(img).scaled(500, 68, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        label.setPixmap(pixmap)

        self.process = QProcess(self)
        self.action_deal_data = QAction("数据处理", self)
        self.action_deal_data.setIcon(QIcon("images/数据处理.png"))
        self.action_deal_data.setObjectName("action_deal_data")
        self.action_deal_data.triggered.connect(self.on_action_deal_data_triggered)

        self.action_new_model = QAction("模型训练", self)
        self.action_new_model.setIcon(QIcon("images/训练.png"))
        self.action_new_model.setObjectName("action_new_model")
        self.action_new_model.triggered.connect(self.on_action_new_model_triggered)

        self.action_new_test = QAction("模型测试", self)
        self.action_new_test.setIcon(QIcon("images/检测.png"))
        self.action_new_test.setObjectName("action_new_test")
        self.action_new_test.triggered.connect(self.on_action_new_test_triggered)

        self.action_global_setting = QAction("参数配置", self)
        self.action_global_setting.setIcon(QIcon("images/设置.png"))
        self.action_global_setting.setObjectName("action_global_setting")
        self.action_global_setting.triggered.connect(self.on_action_global_setting_triggered)

        self.action_exit = QAction("退出程序", self)
        self.action_exit.setIcon(QIcon("images/退出.png"))
        self.action_exit.setObjectName("action_exit")
        self.action_exit.triggered.connect(self.on_action_exit_triggered)

        self.toolBar.addWidget(label)

        self.toolBar.addActions([
            self.action_deal_data,
            self.action_new_model,
            self.action_new_test,
            self.action_global_setting,
            self.action_exit
        ])
        self.toolBar.layout().setSpacing(50)

        self.setWindowTitle("频谱异常检测")
        self.timer_clear_rest_docks = QTimer(self)
        self.timer_clear_rest_docks.timeout.connect(self.clearRestDocks)
        self.timer_clear_rest_docks.start(1000)
        self.models_dict: Dict[str, Dict[str, Dict[str, Union[str, bool, Dict[str, float]]]]] = {}
        self.parent_checked_dcit = {}  # 保存父亲item是否选中
        with open("./qss/psblack.css", "r", encoding="utf-8") as f:
            qss = f.read()
        self.setStyleSheet(qss)
        self.setting_dock.pushButton_addModel.clicked.connect(self.confirmAddModel)
        self.setting_dock.treeWidgetSetting.itemPressed.connect(self.showChangeModelLabelMenu)

        self.id = 0
        self.setting_dock.treeWidgetSetting.itemCheckStateChanged[ETreeWidgetItem, bool].connect(
            self.changeFreqBandLabel)

        self.pop_menu = QMenu(self)
        action = QAction("模型名称修改", self)
        action1 = QAction("阈值修改", self)
        action_del = QWidgetAction(self)
        btn_delete = QPushButton("删除模型", self)
        btn_delete.clicked.connect(self.deleteModel)
        action_del.setDefaultWidget(btn_delete)
        action1.triggered.connect(self.modifyThreshold)
        action.triggered.connect(self.modifyModelLabel)
        self.pop_menu.addActions([action, action1])
        self.pop_menu.addSeparator()

        self.pop_menu.addAction(action_del)
        qss = '''
        *{
            border:none;
            border-radius:0;
            color: #DCDCDC;
            background-color: #484848;
            text-align : left;
            padding-left:20px;
            }
        *:hover{
            background-color:red;
            }
        '''
        btn_delete.setStyleSheet(qss)
        self.loadSetting()

    def changeFreqBandLabel(self, item: ETreeWidgetItem, Itemischecked: bool):
        if item.parent() == self.setting_dock.model_manage:  # 频段
            self.parent_checked_dcit[item.text(0)] = Itemischecked
            return
        lst: List[ETreeWidgetItem] = [self.setting_dock.model_manage.child(i) for i in
                                      range(self.setting_dock.model_manage.childCount())]
        if item.parent() in lst:
            key = item.parent().text(0)
            model_dic = self.models_dict.get(key)
            model_dic[item.text(0)]['checked'] = Itemischecked

    def modifyModelLabel(self):
        text, ok = QInputDialog.getText(self, "模型名称修改", "请输入要修改的模型名称")
        if ok:
            item: ETreeWidgetItem = self.setting_dock.treeWidgetSetting.currentItem()
            key = item.parent().text(0)
            model_dic = self.models_dict.get(key)
            if model_dic is None:
                return
            if text in model_dic.keys():
                QMessageBox.critical(self, "错误提示", "同一频段下不能存在相同名称的模型!")
                return
            value = model_dic[item.text(0)]
            value['name'] = text
            model_dic.pop(item.text(0))
            model_dic[text] = value
            self.ClearAndRePaintModelManage()

    def modifyThreshold(self):
        thresh, ok = QInputDialog.getDouble(self, "阈值修改", "请输入要修改的阈值", min=0, max=1000000000, decimals=3)
        if ok:
            item: QTreeWidgetItem = self.setting_dock.treeWidgetSetting.currentItem()
            key = item.parent().text(0)
            model_dic = self.models_dict.get(key)
            if model_dic is None:
                return
            model_dic[item.text(0)]['thresh'] = "%.3f" % thresh
            self.ClearAndRePaintModelManage()

    def deleteModel(self):
        item: QTreeWidgetItem = self.setting_dock.treeWidgetSetting.currentItem()
        band_key = item.parent().text(0)
        self.models_dict[band_key].pop(item.text(0))
        self.ClearAndRePaintModelManage()
        self.pop_menu.hide()

    def showChangeModelLabelMenu(self, item: QTreeWidgetItem, n: int):
        if not (QGuiApplication.mouseButtons() & Qt.RightButton):
            return
        freq_lst: List[QTreeWidgetItem] = [self.setting_dock.model_manage.child(i) for i in
                                           range(self.setting_dock.model_manage.childCount())]
        if item.parent() is None or item.parent() not in freq_lst:
            return
        self.pop_menu.exec(QCursor.pos())

    def ClearAndRePaintModelManage(self):
        # 先清空所有的item
        cnt = self.setting_dock.model_manage.childCount()
        for i in range(cnt):
            item: QTreeWidgetItem = self.setting_dock.model_manage.child(cnt - i - 1)
            self.setting_dock.model_manage.removeChild(item)

        del_lst = []
        for k in self.models_dict.keys():
            if self.models_dict[k] == {}:
                del_lst.append(k)
        for k in del_lst:
            self.models_dict.pop(k)

        print()
        print(self.models_dict)
        print()

        items: List[ETreeWidgetItem] = [ETreeWidgetItem(self.setting_dock.model_manage, [k, ""]) for k in
                                        self.models_dict.keys()]
        self.setting_dock.model_manage.insertChildren(0, items)

        for index, key in enumerate(self.models_dict.keys()):
            parent = items[index]
            model_dic: Dict[str, Dict[str, Any]] = self.models_dict[key]

            sub_items: List[ETreeWidgetItem] = [ETreeWidgetItem(parent, [k, v['thresh']]) for k, v in model_dic.items()]
            parent.insertChildren(0, sub_items)
            parent.setExpanded(True)
        self.setting_dock.model_manage.setExpanded(True)

        # 添加widget
        for i in range(self.setting_dock.model_manage.childCount()):
            item: QTreeWidgetItem = self.setting_dock.model_manage.child(i)

            item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsUserCheckable)
            if self.parent_checked_dcit.get(item.text(0)) == True:
                item.setCheckState(0, Qt.Checked)
            else:
                item.setCheckState(0, Qt.Unchecked)
            self.setting_dock.treeWidgetSetting.setItemWidget(item, 1, Level_2_Widget(self, subling=item))
            for j in range(item.childCount()):
                sub_item: QTreeWidgetItem = item.child(j)
                # sub_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsUserCheckable)
                if self.models_dict.get(item.text(0))[sub_item.text(0)]['checked'] == True:
                    sub_item.setCheckState(0, Qt.Checked)
                else:
                    sub_item.setCheckState(0, Qt.Unchecked)
                # self.setting_dock.treeWidgetSetting.setItemWidget(sub_item, 0, Level_3_Project_Widget(self, sub_item.text(0)))

    def confirmAddModel(self):
        l = self.setting_dock.min_freq_setting.freq_double_spin_box.value()
        r = self.setting_dock.max_freq_setting.freq_double_spin_box.value()
        if l > r:
            QMessageBox.critical(self, "错误提示", "终止频率不应小于起始频率")
            return
        band_str = "%.3f - %.3f" % (l, r)
        model_dic = self.models_dict.get(band_str, None)
        checkState = self.parent_checked_dcit.get(band_str, None)
        if model_dic is None:
            model_dic = {}
            self.models_dict[band_str] = model_dic
            self.parent_checked_dcit[band_str] = False
        stft_dic = self.getStftSettingFromUI()
        # 将数据写入内存
        while "Unnamed Model %d" % self.unnameid in model_dic.keys():
            self.unnameid += 1
        model_dic["Unnamed Model %d" % self.unnameid] = {
            'name': "Unnamed Model %d" % self.unnameid,
            'thresh': "",
            'checked': False,
            'stft': stft_dic
        }
        self.unnameid += 1
        self.ClearAndRePaintModelManage()

    def clearRestDocks(self):
        for item in self.needToDeleteDocks:
            if isinstance(item, DockWidget):
                item.thread.recover()
            if isinstance(item, TestDockWidget):
                item.recover()
        self.reLayout()

    @staticmethod
    def getReadLength(time_col, window_length, noverlap):
        return (time_col - 3) * (window_length - noverlap) + window_length

    def getTrainFrequencyBand(self):

        # todo 检查参数设置错误",
        train_path = self.setting_dock.train_data_path_widget.gloabal_path.text()
        if train_path == "":
            QMessageBox.critical(self, "错误提示", "请选择训练数据后再试")
            return

        nperseg = self.setting_dock.spinbox_nperseg.value()
        if nperseg <= 0:
            QMessageBox.critical(self, "错误提示", "STFT窗长设置错误")
            return

        noverlap = self.setting_dock.spinbox_noverlap.value()
        if noverlap <= 0:
            QMessageBox.critical(self, "错误提示", "STFT窗函数重叠数设置错误")
            return

        nfft = self.setting_dock.spinbox_nfft.value()
        if nfft <= 0:
            QMessageBox.critical(self, "错误提示", "FFT长度设置错误")
            return
        time_segment = self.setting_dock.spinbox_time_segment.value()
        if time_segment < 3:
            QMessageBox.critical(self, "错误提示", "时频图时间维度长度至少为3")
            return
        sample_freq = self.setting_dock.double_spinbox_sample_freq.value()
        if sample_freq <= 0:
            QMessageBox.critical(self, "错误提示", "采样频率设置错误")
            return

        center_freq = self.setting_dock.double_spinbox_center_freq.value()
        if center_freq <= 0:
            QMessageBox.critical(self, "错误提示", "中心频率设置错误")
            return

        length = self.getReadLength(time_segment, nperseg, noverlap)
        if os.path.getsize(train_path) < length:
            QMessageBox.critical(self, "错误提示", "文件过小, 不能做STFT")
            return

        if not self.created_select_win:
            try:
                with open(train_path, 'rb') as f:
                    content = f.read(length * 4)
                    IQ = struct.unpack("h" * length * 2, content)
                    data = np.array(IQ)
            except Exception as e:
                print(e)
                QMessageBox.critical(self, "错误提示", "读取文件做FFT时发生未知错误")
            y = np.max(IQ_to_PSD(data, length, nfft, sample_freq, noverlap, nperseg), axis=1)
            self.select_win = SelectWindow(self, y, f0=center_freq, fs=sample_freq, nfft=nfft)
            self.select_win.requestChangeMinMaxFreq[tuple].connect(self.changeMinMaxFreq)
            self.select_win.show()
            self.created_select_win = True
        else:
            self.select_win.show()

    def getStftSettingFromUI(self):
        stft_dic = {}
        stft_dic['nperseg'] = self.setting_dock.spinbox_nperseg.value()
        stft_dic['noverlap'] = self.setting_dock.spinbox_noverlap.value()
        stft_dic['nfft'] = self.setting_dock.spinbox_nfft.value()
        stft_dic['time_segment'] = self.setting_dock.spinbox_time_segment.value()
        stft_dic['Fs'] = self.setting_dock.double_spinbox_sample_freq.value()
        stft_dic['F0'] = self.setting_dock.double_spinbox_center_freq.value()
        return stft_dic

    def InitLayout(self):
        self.addDockWidget(Qt.LeftDockWidgetArea, self.setting_dock)

    def isFileNameValid(self, file_name:str):
        if len(file_name) == 0 or len(file_name) >= 255:
            return False
        s = r"^\s\\/:\*\?\"<>\|[^\s\\/:\\?\"<>\|\.]$"
        pattern = re.compile(s)
        pass

    def __connectSlot(self):
        self.windowSizeChanged.connect(self.reLayout)
        self.setting_dock.pushButton_saveSetting.clicked.connect(self.saveSetting)
        self.setting_dock.min_freq_setting.pushButton.clicked.connect(self.getTrainFrequencyBand)
        self.setting_dock.max_freq_setting.pushButton.clicked.connect(self.getTrainFrequencyBand)

    def loadSetting(self):
        try:
            with open("./config/parameter.json", "r", encoding='utf8') as f:
                setting = json.load(f)
        except Exception as e:
            print(e)
            return
        try:
            path_dic = setting['path setting']
            self.setting_dock.path_widget.gloabal_path.setText(path_dic['path'])
            self.setting_dock.picture_save_linedit.setText(path_dic['picture name'])

            stft_dic = setting['STFT setting']
            self.setting_dock.spinbox_nperseg.setValue(stft_dic['nperseg'])
            self.setting_dock.spinbox_noverlap.setValue(stft_dic['noverlap'])
            self.setting_dock.spinbox_nfft.setValue(stft_dic['nfft'])
            self.setting_dock.spinbox_time_segment.setValue(stft_dic['time_segment'])
            self.setting_dock.double_spinbox_sample_freq.setValue(stft_dic['Fs'])
            self.setting_dock.double_spinbox_center_freq.setValue(stft_dic['F0'])

            train_dic = setting['train setting']
            self.setting_dock.train_data_path_widget.gloabal_path.setText(train_dic['train data path'])
            self.setting_dock.min_freq_setting.freq_double_spin_box.setValue(train_dic['start Frequency'])
            self.setting_dock.max_freq_setting.freq_double_spin_box.setValue(train_dic['end Frequency'])

            self.models_dict = setting['model management']
            self.ClearAndRePaintModelManage()
        except Exception as e:
            print("./config/parameter.json loaded failed: %s" % e)

    def saveSetting(self):
        # 1. 设置除模型管理外的其他设置
        setting = {}
        path_dic = {}
        path_dic['path'] = self.setting_dock.path_widget.gloabal_path.text()
        path_dic['picture name'] = self.setting_dock.picture_save_linedit.text()
        setting['path setting'] = path_dic

        stft_dic = {}
        stft_dic['nperseg'] = self.setting_dock.spinbox_nperseg.value()
        stft_dic['noverlap'] = self.setting_dock.spinbox_noverlap.value()
        stft_dic['nfft'] = self.setting_dock.spinbox_nfft.value()
        stft_dic['time_segment'] = self.setting_dock.spinbox_time_segment.value()
        stft_dic['Fs'] = self.setting_dock.double_spinbox_sample_freq.value()
        stft_dic['F0'] = self.setting_dock.double_spinbox_center_freq.value()
        setting['STFT setting'] = stft_dic

        train_dic = {}
        train_dic['train data path'] = self.setting_dock.train_data_path_widget.gloabal_path.text()
        train_dic['start Frequency'] = self.setting_dock.min_freq_setting.freq_double_spin_box.value()
        train_dic['end Frequency'] = self.setting_dock.max_freq_setting.freq_double_spin_box.value()
        setting['train setting'] = train_dic
        # 2. 保存模型管理设置
        setting['model management'] = self.models_dict
        # 3. 写入文件
        with open("./config/parameter.json", "w", encoding='utf8') as f:
            json.dump(setting, f)

    def changeMinMaxFreq(self, data: tuple):
        self.setting_dock.min_freq_setting.freq_double_spin_box.setValue(data[0])
        self.setting_dock.max_freq_setting.freq_double_spin_box.setValue(data[1])

    def resizeEvent(self, size: QResizeEvent):
        self.windowSizeChanged.emit()

    def reLayout(self) -> None:
        if len(self.docks) >= 1:
            self.resizeDocks([self.docks[0]], [self.width()], Qt.Horizontal)
            self.resizeDocks([self.docks[0]], [self.height()], Qt.Vertical)
            return
        pass
        # print("relayout event")

    @pyqtSlot()
    def on_action_global_setting_triggered(self):
        self.setting_dock.show()

    # @pyqtSlot()
    # def on_action_new_model_triggered(self):
    #     try:
    #         print("新建模型")
    #         if self.setting_dock.comboBox_method.currentText() == '单频段单模型':
    #             dialog = TrainDialog(self)
    #             if dialog.exec_() == QDialog.Accepted:
    #                 self.freq_text = dialog.comboBox_freq.currentText()
    #                 self.currentIndex = dialog.comboBox_freq.currentIndex()
    #             else:
    #                 return
    #             a = DockWidget(self, n=3, name=self.freq_text, index=self.currentIndex)
    #             a.setWindowTitle("单频段单模型: %s" % self.freq_text)
    #             a.setObjectName("DockWidget_{}".format(self.dock_id))
    #             a.Label_2.hide()
    #             a.lineEdit_train_label_save_path.hide()
    #             del a.label_2
    #             del a.lineEdit_train_label_save_path
    #             a.pushButton_get_train_label_save_path.hide()
    #             a.ComboBox_train_freq_band.addItems(self.setting_dict["阈值设置"].keys())
    #             a.ComboBox_train_freq_band.setCurrentText(self.freq_text)
    #
    #         elif self.setting_dock.comboBox_method.currentText() == '多频段单模型':
    #             self.freq_text = ""
    #             a = DockWidget(self, n=3, name="多频段单模型", index=-1, MutiTrain=True)
    #             a.setWindowTitle("多频段单模型")
    #             a.setObjectName("DockWidget_{}".format(self.dock_id))
    #             a.ComboBox_train_freq_band.hide()
    #             a.Label.hide()
    #             # a.ComboBox_train_freq_band.addItems(self.setting_dict["阈值设置"].keys())
    #             # a.ComboBox_train_freq_band.setCurrentText(self.freq_text)
    #         self.dock_id += 1
    #         self.docks.append(a)
    #         self.docks[-1].show()
    #         if len(self.docks) == 1:
    #             self.addDockWidget(Qt.RightDockWidgetArea, self.docks[-1])
    #             self.resizeDocks([self.docks[-1]], [self.width()], Qt.Horizontal)
    #             self.resizeDocks([self.docks[-1]], [self.height()], Qt.Vertical)
    #         else:
    #             self.tabifyDockWidget(self.docks[-2], self.docks[-1])
    #     except Exception as e:
    #         print("NO. %d %s" % (sys._getframe().f_lineno, e))

    def findMemorySetting(self, band: str, name: str):
        pass

    @pyqtSlot()
    def on_action_new_model_triggered(self):
        print("模型训练")
        # 1. 判断是否有选中的模型
        model_names = []
        items: List[QTreeWidgetItem] = []
        for i in range(self.setting_dock.model_manage.childCount()):
            item: QTreeWidgetItem = self.setting_dock.model_manage.child(i)
            for j in range(item.childCount()):
                sub_item: QTreeWidgetItem = item.child(j)
                if sub_item.checkState(0) == Qt.Checked:
                    model_names.append((item.text(0), sub_item.text(0)))
                    items.append(sub_item)
        if len(model_names) == 0:
            QMessageBox.critical(self, "错误提示", "您还没有选中要训练的模型, 请选中后再试!")
            return
        # 2. 根据选中的模型创建窗口
        for i, model in enumerate(model_names):
            item = items[i]
            item.setCheckState(0, Qt.Unchecked)
            win_title = "Train: %s - %s" % (model[0], model[1])

            a = DockWidget(self, n=3, name=item.text(0), band=item.parent().text(0), stftsetting=self.models_dict[model[0]][model[1]]['stft'])
            a.setWindowTitle(win_title)
            a.setObjectName("DockWidget_{}".format(self.dock_id))

            path = self.setting_dock.path_widget.gloabal_path.text()
            if path == "":
                path = self.setting_dock.path_widget.gloabal_path.placeholderText()
            picture_path = self.setting_dock.picture_save_linedit.text()
            if picture_path == "":
                picture_path = self.setting_dock.picture_save_linedit.placeholderText()
            a.lineEdit_model_save_path.setText(os.path.join(path, model[0], model[1], "model"))
            a.lineEdit_picture_save_path.setText(os.path.join(path, model[0], model[1], picture_path))
            a.lineEdit_model_name.setText(model[1])
            a.lineEdit_show_train_band.setText(item.parent().text(0))
            self.dock_id += 1
            self.docks.append(a)
            self.docks[-1].show()
            if len(self.docks) == 1:
                self.addDockWidget(Qt.RightDockWidgetArea, self.docks[-1])
                self.resizeDocks([self.docks[-1]], [self.width()], Qt.Horizontal)
                self.resizeDocks([self.docks[-1]], [self.height()], Qt.Vertical)
            else:
                self.tabifyDockWidget(self.docks[-2], self.docks[-1])

    @pyqtSlot()
    def on_action_new_test_triggered(self):

        print("模型测试")
        model_names = []
        items: List[QTreeWidgetItem] = []
        for i in range(self.setting_dock.model_manage.childCount()):
            item: QTreeWidgetItem = self.setting_dock.model_manage.child(i)
            for j in range(item.childCount()):
                sub_item: QTreeWidgetItem = item.child(j)
                if sub_item.checkState(0) == Qt.Checked:
                    model_names.append((item.text(0), sub_item.text(0), sub_item.text(1)))
                    items.append(sub_item)
        if len(model_names) == 0:
            QMessageBox.critical(self, "错误提示", "您还没有选中要测试的模型, 请选中后再试!")
            return
        print(model_names)

        error_msg = ""
        for index, (model_band, model_name, model_thresh) in enumerate(model_names):
            item = items[index]
            item.setCheckState(0, Qt.Unchecked)
            if model_thresh == "":
                error_msg += f"{model_band}频段——模型{model_name}\n"
                continue

            win_title = "Test: %s - %s" % (model_band, model_name)
            a = TestDockWidget(self, threshold=float(model_thresh), model_name = model_name, freq_band=model_band, stftsetting=self.models_dict[model_band][model_name]['stft'])
            a.label_ab.setFixedSize(QSize(15, 15))
            a.lineEdit_test_freq_band.setText(model_band)
            path = self.setting_dock.path_widget.gloabal_path.text()
            if path == "":
                path = self.setting_dock.path_widget.gloabal_path.placeholderText()
            a.lineEdit_model_save_path.setText(os.path.join(path, model_band, model_name, "model"))
            a.setWindowTitle(win_title)
            a.setObjectName("TestDockWidget_{}".format(self.dock_id))
            self.dock_id += 1
            self.docks.append(a)
            self.docks[-1].show()
            if len(self.docks) == 1:
                self.addDockWidget(Qt.RightDockWidgetArea, self.docks[-1])
                self.resizeDocks([self.docks[-1]], [self.width()], Qt.Horizontal)
                self.resizeDocks([self.docks[-1]], [self.height()], Qt.Vertical)
            else:
                self.tabifyDockWidget(self.docks[-2], self.docks[-1])
        if error_msg != "":
            QMessageBox.critical(self, "错误提示", f"以下频段模型:\n%s由于没有检测阈值无法进行检测, 请训练模型或设置阈值后再试!" % error_msg)

    @pyqtSlot()
    def on_action_exit_triggered(self):
        self.deleteLater()

    def output(self):
        s = self.process.readAllStandardOutput()
        s = str(s, encoding="utf-8")
        print(s)

    @pyqtSlot()
    def on_action_deal_data_triggered(self):
        self.process.readyReadStandardOutput.connect(self.output)
        nfft = self.setting_dock.spinbox_nfft.value()
        nperseg = self.setting_dock.spinbox_nperseg.value()
        noverlap = self.setting_dock.spinbox_noverlap.value()
        sample_freq = self.setting_dock.double_spinbox_sample_freq.value()
        time_segment = self.setting_dock.spinbox_time_segment.value()

        print(str(nfft), str(nperseg), str(noverlap), str(sample_freq), str(time_segment))
        self.process.start("python",
                           [".\windows\deal_data_win.py", str(nfft), str(nperseg), str(noverlap), str(sample_freq),
                            str(time_segment)])

    # def paintEvent(self, a0: QPaintEvent) -> None:
    #     img = QImage()
    #     img.load("./images/20200613221528.jpg")
    #     pixmap = QPixmap.fromImage(img).scaled(self.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
    #     painter = QPainter(self)
    #     painter.drawPixmap(self.rect(), pixmap)
    def closeEvent(self, a0: QCloseEvent) -> None:
        # for item in self.docks:
        #     item.deleteLater()
        pass


TextStyle = """
    QMessageBox QPushButton[text="OK"] {
        qproperty-text: "好的";
    }
    QMessageBox QPushButton[text="Open"] {
        qproperty-text: "打开";
    }
    QMessageBox QPushButton[text="Save"] {
        qproperty-text: "保存";
    }
    QMessageBox QPushButton[text="Cancel"] {
        qproperty-text: "取消";
    }
    QMessageBox QPushButton[text="Close"] {
        qproperty-text: "关闭";
    }
    QMessageBox QPushButton[text="Discard"] {
        qproperty-text: "不保存";
    }
    QMessageBox QPushButton[text="Don't Save"] {
        qproperty-text: "不保存";
    }
    QMessageBox QPushButton[text="Apply"] {
        qproperty-text: "应用";
    }
    QMessageBox QPushButton[text="Reset"] {
        qproperty-text: "重置";
    }
    QMessageBox QPushButton[text="Restore Defaults"] {
        qproperty-text: "恢复默认";
    }
    QMessageBox QPushButton[text="Help"] {
        qproperty-text: "帮助";
    }
    QMessageBox QPushButton[text="Save All"] {
        qproperty-text: "保存全部";
    }
    QMessageBox QPushButton[text="&Yes"] {
        qproperty-text: "是";
    }
    QMessageBox QPushButton[text="Yes to &All"] {
        qproperty-text: "全部都是";
    }
    QMessageBox QPushButton[text="&No"] {
        qproperty-text: "不";
    }
    QMessageBox QPushButton[text="N&o to All"] {
        qproperty-text: "全部都不";
    }
    QMessageBox QPushButton[text="Abort"] {
        qproperty-text: "终止";
    }
    QMessageBox QPushButton[text="Retry"] {
        qproperty-text: "重试";
    }
    QMessageBox QPushButton[text="Ignore"] {
        qproperty-text: "忽略";
    }
    """
StyleSheet = TextStyle

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet(StyleSheet)
    font = QFont("微软雅黑", 8.5)
    app.setFont(font)
    win = MainWin()
    win.showMaximized()
    win.show()
    sys.exit(app.exec_())
